home *** CD-ROM | disk | FTP | other *** search
- /* October 95 Programmer's challenge solution.
- MindReader - By Xan Gregg, Durham, NC.
-
- I try to minimize the number of guesses without
- adding too much complexity too our the code. First
- I figure out how many of each color are present
- in the answer by essentially repeatedly guessing
- all of each color.
-
- Then I figure out the correct positions one at a time
- starting at slot 0. I exchange it with each other
- slot (one at a time) until the correct color is found.
- When there is a change in the numCorrect response from
- checkGuess I can tell which of the two slots caused
- the change by looking at my remembered information or,
- if necessary, by performing a second guess with one of
- the colors in both slots.
-
- The "remembered information" includes keeping track
- of colors that were determined (via the numCorrect
- change) to be wrong before and/or a swap is made. This
- doesn't help out too often, but it doesn't take much
- time to record compared to calling checkGuess.
-
- While the outer loop determines the color of
- each slot "left-to-right" (0 to n-1), I found
- that indexing the inner loop right-to-left
- instead of left-to-right increased the speed
- by 30% - 40%. I wish I understood why!
-
- Oddly, the checkGuess function spends most of its
- time figuring out the numWrong value, which we
- generally ignore.
- */
-
- typedef void (*CheckGuessProcPtr)(
- unsigned char *theGuess,
- unsigned short *numInCorrectPos,
- unsigned short *numInWrongPos);
-
-
- void MindReader(
- unsigned char theAnswer[],
- CheckGuessProcPtr checkGuess,
- unsigned short answerLength,
- unsigned short numColors);
-
- #define kMaxLength 16
-
- #define Bit(color) (1L << (long) (color))
-
-
- void MindReader(unsigned char guess[],
- CheckGuessProcPtr checkGuess,
- unsigned short answerLength,
- unsigned short numColors)
- {
- long prevColorsFound;
- long colorsFound;
- long curColor;
- long i, j;
- long curCorrect;
- long numOfColor[kMaxLength + 1]; /* 1-based */
- Boolean isCorrect[kMaxLength];
- long possibilities[kMaxLength]; /* bit fields */
- long colorBit1;
- long colorBit2;
- char color1;
- char color2;
- long delta;
- unsigned short newCorrect;
- unsigned short newWrong;
-
- /* first find the correct set of colors */
- colorsFound = 0;
- curColor = 1;
- while (colorsFound < answerLength)
- {
- for (i = colorsFound; i < answerLength; i++)
- guess[i] = curColor;
- (*checkGuess)(guess, &newCorrect, &newWrong);
- prevColorsFound = colorsFound;
- colorsFound = newCorrect + newWrong;
- numOfColor[curColor] = colorsFound - prevColorsFound;
- curColor++;
- }
-
- /* now work on the order */
- for (i = 0; i < answerLength; i++)
- {
- isCorrect[i] = false;
- possibilities[i] = -1; /* all colors */
- }
- curCorrect = newCorrect;
- /* step through every slot, starting at 0 */
- for (i = 0; curCorrect < answerLength; i++)
- {
- if (isCorrect[i])
- continue;
- color1 = guess[i];
- colorBit1 = Bit(color1);
- /* try swapping slot i with every other open */
- /* slot, starting with the last one */
- j = answerLength;
- nextSubSlot:
- j--;
- if (guess[i] == guess[j])
- goto nextSubSlot;
- if (isCorrect[j])
- goto nextSubSlot;
- color2 = guess[j];
- colorBit2 = Bit(color2);
- if ((possibilities[i] & colorBit2) == 0)
- goto nextSubSlot; /* no hope here */
- /* swap slots i & j and check result */
- guess[i] = color2;
- guess[j] = color1;
- (*checkGuess)(guess, &newCorrect, &newWrong);
- delta = newCorrect - curCorrect;
- if (delta >= 0)
- if (delta == 0)
- { /* either both are incorrect OR */
- /* one is correct and answer[i]==answer[j] */
- guess[i] = color1;
- guess[j] = color2;
- if (numOfColor[color1] == 1)
- { /* color1 can't be in both places */
- possibilities[i] &= ~colorBit1;
- possibilities[j] &= ~colorBit1;
- }
- if (numOfColor[color2] == 1)
- { /* color2 can't be in both places */
- possibilities[i] &= ~colorBit2;
- possibilities[j] &= ~colorBit2;
- }
- }
- else if (delta == 1)
- { /* both were wrong, now one is correct */
- /* find out which is correct */
- curCorrect = newCorrect;
- if ((possibilities[j] & colorBit1) == 0)
- { /* i must be color2 */
- possibilities[j] &= ~colorBit2;
- numOfColor[color2] -= 1;
- goto nextSlot;
- }
- else if ((possibilities[i] & colorBit2) == 0)
- { /* j must be color1 */
- isCorrect[j] = true;
- possibilities[i] &= ~colorBit1;
- numOfColor[color1] -= 1;
- color1 = color2;
- colorBit1 = colorBit2;
- }
- else
- { /* we'll have to make another guess to */
- /* see which is correct */
- guess[i] = color1;
- (*checkGuess)(guess, &newCorrect, &newWrong);
- if (newCorrect == curCorrect)
- { /* j must be color1 */
- possibilities[i] &=
- (~(colorBit1 | colorBit2));
- isCorrect[j] = true;
- guess[i] = color2;
- numOfColor[color1] -= 1;
- color1 = color2;
- colorBit1 = colorBit2;
- }
- else
- { /* i must be color2 */
- possibilities[j] &=
- (~(colorBit1 | colorBit2));
- guess[i] = color2;
- numOfColor[color2] -= 1;
- goto nextSlot;
- }
- }
- }
- else /* delta == 2 */
- { /* both were wrong, now both correct */
- isCorrect[j] = true;
- numOfColor[color1] -= 1;
- numOfColor[color2] -= 1;
- curCorrect = newCorrect;
- goto nextSlot;
- }
- else /* delta < 0 */
- if (delta == -1)
- { /* one was correct before swap, now neither is */
- guess[i] = color1;
- guess[j] = color2;
- if ((possibilities[i] & colorBit1) == 0)
- { /* color2 in slot j was correct */
- isCorrect[j] = true;
- numOfColor[color2] -= 1;
- possibilities[i] &= ~colorBit2;
- }
- else if ((possibilities[j] & colorBit2) == 0)
- { /* color1 in slot i was correct */
- possibilities[j] &= ~colorBit1;
- numOfColor[color1] -= 1;
- goto nextSlot;
- }
- else
- { /* we'll have to make another guess to */
- /* see which was correct */
- guess[j] = color1;
- (*checkGuess)(guess, &newCorrect, &newWrong);
- if (newCorrect == curCorrect)
- { /* color1 in slot i was correct */
- possibilities[j] &=
- (~(colorBit1 | colorBit2));
- guess[j] = color2;
- numOfColor[color1] -= 1;
- goto nextSlot;
- }
- else
- { /* color2 in slot j was correct */
- possibilities[i] &=
- (~(colorBit1 | colorBit2));
- guess[j] = color2;
- isCorrect[j] = true;
- numOfColor[color2] -= 1;
- }
- }
- }
- else /* delta == -2 */
- { /* both were already correct */
- guess[i] = color1;
- guess[j] = color2;
- isCorrect[j] = true;
- numOfColor[color1] -= 1;
- numOfColor[color2] -= 1;
- goto nextSlot;
- }
- goto nextSubSlot;
- nextSlot: ;
- }
- done: ;
- }
-
-
-
-
-